package main

import (
	"database/sql"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"

	"test.com/fusion"
	"test.com/worlddb"
)

type SObjPrototype struct {
	SObjName string                 `json:"sobjName"`
	SObjDesc string                 `json:"sobjDesc"`
	SObjInfo *worlddb.SObjPrototype `json:"sobjInfo"`
}

type sobjWebPrototype struct {
	SObjPrototype
}

func handleGetSObjTemplates(w http.ResponseWriter, r *http.Request) {
	allTemplates := map[string]interface{}{
		"SObjPrototype_CostItem": fusion.MarshalEntityToInterface(
			new(worlddb.SObjPrototype_CostItem), "json"),
	}
	jsonData, err := json.Marshal(allTemplates)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, jsonData)
}

func handleGetSObjDialogArgs(w http.ResponseWriter, r *http.Request) {
	scriptFiles, err := getAllScriptable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsRows, err := getAllLoot4DialogTable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	tpRows, err := getAllTeleport4DialogTable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	spellRows, err := getAllSpell4DialogTable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	questRows, err := getAllQuest4DialogTable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	itemRows, err := getAllItem4DialogTable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	dialogArgs := map[string]interface{}{
		"scriptFiles": scriptFiles,
		"lsRows":      lsRows,
		"tpRows":      tpRows,
		"spellRows":   spellRows,
		"questRows":   questRows,
		"itemRows":    itemRows,
	}
	jsonData, err := json.Marshal(dialogArgs)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, jsonData)
}

func handleGetSObjEnumType(w http.ResponseWriter, r *http.Request) {
	enumTypes := map[string]interface{}{
		"ScriptType": getEnumScriptType(),
	}
	jsonData, err := json.Marshal(enumTypes)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, jsonData)
}

func handleGetSObjTreeView(w http.ResponseWriter, r *http.Request) {
	handleGetEditorTreeView(
		w, r, worlddb.EditorTreeView_Type_SObj, getAllSObjNames)
}

func handleSaveSObjTreeView(w http.ResponseWriter, r *http.Request) {
	handleSaveEditorTreeView(w, r, worlddb.EditorTreeView_Type_SObj)
}

func handleGetSObjInstance(w http.ResponseWriter, r *http.Request) {
	sobjTypeId, err := strconv.ParseUint(r.FormValue("SObjTypeId"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	sobjData, err := getSObjInstanceJsonData(worldDB, uint32(sobjTypeId))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, sobjData)
}

func handleNewSObjInstance(w http.ResponseWriter, r *http.Request) {
	sobjName, sobjDesc := r.FormValue("SObjName"), r.FormValue("SObjDesc")
	if sobjName == "" {
		http.Error(w, "empty static object name.", http.StatusBadRequest)
		return
	}
	var sobjTypeId uint32
	err := fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		sobjTypeId, err = newSObjInstance(tx, sobjName, sobjDesc)
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	sobjData, err := getSObjInstanceJsonData(worldDB, sobjTypeId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, sobjData)
}

func handleCopySObjInstance(w http.ResponseWriter, r *http.Request) {
	sobjTypeId, err := strconv.ParseUint(r.FormValue("SObjTypeId"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var ID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		ID, err = copySObjInstance(worldDB, tx, uint32(sobjTypeId))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	sobjData, err := getSObjInstanceJsonData(worldDB, ID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, sobjData)
}

func handleDeleteSObjInstance(w http.ResponseWriter, r *http.Request) {
	sobjTypeId, err := strconv.ParseUint(r.FormValue("SObjTypeId"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) error {
		return deleteSObjInstance(tx, uint32(sobjTypeId))
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeOKResponseData(w)
}

func handleSaveSObjInstance(w http.ResponseWriter, r *http.Request) {
	sobjData, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	var sobjProto SObjPrototype
	if err = json.Unmarshal(sobjData, &sobjProto); err != nil {
		http.Error(w, err.Error(), http.StatusNotAcceptable)
		return
	}
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) error {
		return saveSObjInstance(tx, &sobjProto)
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeOKResponseData(w)
}
